/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.area.field.shape;

import java.awt.Dialog;
import nl.cloudfarming.client.model.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JLabel;
import net.miginfocom.swing.MigLayout;
import nl.cloudfarming.client.area.AreaEventKey;
import nl.cloudfarming.client.area.AreaService;
import nl.cloudfarming.client.area.field.AreaFieldModule;
import nl.cloudfarming.client.area.field.FieldAreaService;
import nl.cloudfarming.client.geoviewer.EditLayerAction;
import nl.cloudfarming.client.geoviewer.events.LayerEventKey;
import nl.cloudfarming.client.geoviewer.events.RemovedLayerEvent;
import nl.cloudfarming.client.logging.AppLogFactory;
import nl.cloudfarming.client.logging.AppLogger;
import nl.cloudfarming.client.model.Bean;
import nl.cloudfarming.client.model.Field;
import nl.cloudfarming.eventbus.BaseGuiEventProducer;
import nl.cloudfarming.eventbus.GuiEvent;
import nl.cloudfarming.eventbus.GuiEventKey;
import org.jdesktop.swingx.JXPanel;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.openide.util.lookup.ServiceProvider;

/**
 * Action to save the layerobjects on the importlayer
 * @author Timon Veenstra
 */
@ServiceProvider(service = EditLayerAction.class)
public class SaveImportLayerAction extends EditLayerAction {

    private Dialog dlg;
    private ImportLayer layer;
    private static final String SAVE_IMPORT_LAYER_DIALOG_TITLE = NbBundle.getMessage(AreaFieldModule.class, "action.save_import_layer.dialog.title");
    private static final String SAVE_IMPORT_LAYER_ACTION = NbBundle.getMessage(AreaFieldModule.class, "action.save_import_layer.dialog.action_name");
    private static final String SAVE_IMPORT_LAYER_DIALOG_OK = NbBundle.getMessage(AreaFieldModule.class, "action.save_import_layer.dialog.button.ok");
    private static final String SAVE_IMPORT_LAYER_DIALOG_CANCEL = NbBundle.getMessage(AreaFieldModule.class, "action.save_import_layer.dialog.button.cancel");
    private static final String SAVE_IMPORT_LAYER_DIALOG_TEXT = NbBundle.getMessage(AreaFieldModule.class, "action.save_import_layer.dialog.text");
    private static final String SAVE_IMPORT_LAYER_LOG_FINISHED_SUCCESS = NbBundle.getMessage(AreaFieldModule.class, "action.save_import_layer.loginfo.finished_success");
    private static final AppLogger LOG = AppLogFactory.getLogger(AreaFieldModule.class);
    /**
     * never use directly, always use getAreaService();
     */
    private AreaService areaService;

    public void setAreaService(AreaService areaService) {
        this.areaService = areaService;
    }

    /**
     * 
     * @return The areaservice
     */
    public AreaService getAreaService() {
        if (areaService == null) {
            this.areaService = new FieldAreaService();
        }
        return areaService;
    }

    public SaveImportLayerAction() {
        putValue(NAME, SAVE_IMPORT_LAYER_ACTION);
    }

    public void saveImportLayer() {
        assert layer != null;

        if (!(layer instanceof ImportLayer)) {
            return;
        }
        Map<Shape.ShapeType, Integer> totals = new EnumMap<Shape.ShapeType, Integer>(Shape.ShapeType.class);
        for (Shape.ShapeType t : Shape.ShapeType.values()) {
            totals.put(t, 0);
        }

        ImportLayer importLayer = (ImportLayer) layer;
        List<ShapeLayerObject> shapeLayerObjects = importLayer.getObjects();

        for (ShapeLayerObject shapeLayerObject : shapeLayerObjects) {
            Shape shape = shapeLayerObject.getObject();
            Bean bean = parseShape(shape);
            if (bean != null) {
                totals.put(shape.getType(), totals.get(shape.getType()) + 1);
                //TODO add support of other types 
                //(e.g. partfield, etc?)
                if (bean instanceof Field) {
                    getAreaService().createNewField((Field) bean);
                }
            }

        }
        RemovedLayerEvent event = new RemovedLayerEvent(importLayer);
        new LayerEventProducer().triggerEvent(event);


        new AreaEventProducer().triggerEvent(new GuiEvent() {

            @Override
            public GuiEventKey getKey() {
                return AreaEventKey.FIELDS_IMPORTED;
            }

            @Override
            public Object getContent() {
                return null;
            }
        });
        for (Shape.ShapeType shapeType : totals.keySet()) {
            if (totals.get(shapeType) > 0) {
                LOG.info(NbBundle.getMessage(AreaFieldModule.class, "action.save_import_layer.loginfo.amount", totals.get(shapeType), shapeType.toString()));
            }
        }

        LOG.info(SAVE_IMPORT_LAYER_LOG_FINISHED_SUCCESS);
    }

    private Bean parseShape(Shape shape) {
        if (shape == null || shape.getType() == null || shape.getGeometry() == null) {
            return null;
        }
        switch (shape.getType()) {
            case FIELD:
                return new Field.Builder().setWKT(shape.getGeometry().toText()).setName(shape.getName()).setAcreage(shape.getGeometry().getArea()).build();
        }
        return null;
    }

    /**
     * Creates the dialog ok button
     *
     * @return The OK button + its action
     */
    private JButton getOkButton() {
        JButton jButtonOK = new JButton();
        jButtonOK.setText(SAVE_IMPORT_LAYER_DIALOG_OK);
        jButtonOK.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                dlg.setVisible(false);
                saveImportLayer();
            }
        });
        return jButtonOK;
    }

    /**
     * Creates the dialog cancel button
     * @return The Cancel button + its action
     */
    private JButton getCancelButton() {
        JButton jButtonCancel = new JButton();
        jButtonCancel.setText(SAVE_IMPORT_LAYER_DIALOG_CANCEL);
        jButtonCancel.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                dlg.setVisible(false);
            }
        });
        return jButtonCancel;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        layer = Utilities.actionsGlobalContext().lookup(ImportLayer.class);
        assert layer != null;
        //
        // calculate totals per type
        //
        Map<Shape.ShapeType, Integer> totals = new EnumMap<Shape.ShapeType, Integer>(Shape.ShapeType.class);
        int empty = 0;
        for (Shape.ShapeType t : Shape.ShapeType.values()) {
            totals.put(t, 0);
        }

        for (ShapeLayerObject layerObject : layer.getObjects()) {
            Shape.ShapeType st = layerObject.getObject().getType();
            if (st != null) {
                totals.put(st, totals.get(st) + 1);
            } else {
                empty++;
            }
        }
        //
        // populate the panel with the information about what the user is about to save
        //
        JXPanel panel = new JXPanel(new MigLayout("wrap 2"));
        panel.add(new JLabel(SAVE_IMPORT_LAYER_DIALOG_TEXT), "wrap");

        for (Shape.ShapeType st : totals.keySet()) {
            if (totals.get(st) > 0) {
                panel.add(new JLabel(st.toString() + " :"));
                panel.add(new JLabel(totals.get(st) + ""));
            }
        }
        if (empty > 0) {
            panel.add(new JLabel("empty :"));
            panel.add(new JLabel(empty + ""));
        }
        //
        // create the dialog and add the ok and cancel buttons
        //
        DialogDescriptor dd = new DialogDescriptor(panel, SAVE_IMPORT_LAYER_DIALOG_TITLE);
        dd.setOptions(new Object[]{getOkButton(), getCancelButton()});
        dlg = DialogDisplayer.getDefault().createDialog(dd);
        dlg.setVisible(true);
    }

    private class AreaEventProducer extends BaseGuiEventProducer {

        public AreaEventProducer() {
            super(AreaEventKey.class);
        }
    }

    private class LayerEventProducer extends BaseGuiEventProducer {

        public LayerEventProducer() {
            super(LayerEventKey.class);
        }
    }
}
